package com.grace.portal.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

/**
 * 
 * 连接工具类
 * @author zyj
 *
 */
public class HttpClientUtil {
	
	private static final Logger log = Logger.getLogger(HttpClientUtil.class);  
	
	//字符编码
	private static final String CHARSET = "UTF-8";
	 
	//httpClient对象
	private HttpClient httpClient;

	private static HttpClientUtil httpClientUtil = new HttpClientUtil();
	
	//单例模式返回
	public static HttpClientUtil getInstance(){
		return httpClientUtil;
	}
	
	public HttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}
	
	private HttpClientUtil(){
		//设置访问协议 ,使用默认的 socket factories 注册 "http" & "https" protocol scheme
		SchemeRegistry schreg = SchemeRegistryFactory.createDefault();
		//已上面的代码意义是一样的
		//SchemeRegistry schreg = new SchemeRegistry();    
	    //schreg.register(new Scheme("http",80,PlainSocketFactory.getSocketFactory()));   
	    //schreg.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); 
		//构造httpclient池,多连接的线程安全的管理器。
	    PoolingClientConnectionManager pccm = new PoolingClientConnectionManager(schreg);  
	    pccm.setDefaultMaxPerRoute(500); //每个主机的最大并行链接数   
	    pccm.setMaxTotal(2000);          //客户端总并行链接最大数  
	    
	    // 设置组件参数, HTTP协议的版本,1.1/1.0/0.9   
	    HttpParams params = new BasicHttpParams();
	    //设置连接超时时间   
	    params.setParameter(CoreConnectionPNames.SO_REUSEADDR, true);
	    params.setParameter(CoreConnectionPNames.TCP_NODELAY, true);
	    params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);//设置请求超时10秒钟  
	    params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000);   //设置等待数据超时时间10秒钟
	    params.setParameter(CoreConnectionPNames.SO_KEEPALIVE, true);
	    
	    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
	    HttpProtocolParams.setUserAgent(params, "HttpComponents/1.1"); 
	    //HttpProtocolParams.setUseExpectContinue(params, true);
		HttpProtocolParams.setUseExpectContinue(params, false);
		HttpProtocolParams.setContentCharset(params, CHARSET);
		
		HttpClientParams.setCookiePolicy(params,CookiePolicy.IGNORE_COOKIES);
		
		httpClient = new DefaultHttpClient(pccm, params);
		
		//当程序关闭时需要关闭所有的连接
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				if(log.isDebugEnabled()){
					log.debug("HttpClientUtil shutdownConnection...");
				}
				HttpClientUtil.this.shutdownConnection();
			}
		});
	}
	
	/**
	 * 处理用户请求
	 * @param request httppost和httpget等请求对象
	 * @return HttpResponse http响应对象
	 * @throws IOException
	 */
	public HttpResponse execute(HttpRequestBase request) throws IOException {
		if (null == request) {
			throw new IllegalArgumentException("The request is null,can't execute request.");
		}
		return httpClient.execute(request);
	}
	
	/**
	 * 处理请求结果集
	 * @param httpResponse 请求返回对象
	 * @return 解析返回请求结果字符串
	 * @throws IOException 
	 */
	public String getContent(HttpResponse httpResponse) throws IOException {
		Header headers = httpResponse.getEntity().getContentEncoding();
		String result = "";
		//判断响应压缩则获取压缩数据
		if (headers != null) {
			InputStream inputStream = null;
			try {
				byte[] readBytes = new byte[8192];
				inputStream = new GZIPInputStream(httpResponse.getEntity().getContent());
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				int length = 0;
				while ((length = inputStream.read(readBytes)) != -1) {
					baos.write(readBytes, 0, length);
				}
				result = baos.toString(CHARSET);
			}finally{
				if(null != inputStream){
					inputStream.close();
				}
			}
		} else {
			result = EntityUtils.toString(httpResponse.getEntity(), CHARSET);
		}
		return result;
	}
	
	/**
	 * 根据具体的httpclient对象处理用户请求
	 * @param httpClient 用户使用的httpclient对象
	 * @param request httppost和httpget等请求对象
	 * @return HttpResponse http响应对象
	 * @throws IOException
	 */
	public HttpResponse service(HttpClient httpClient,HttpRequestBase request) throws IOException {
		if (null == httpClient) {
			throw new IllegalArgumentException("The httpClient is null,can't execute request.");
		}
		if (null == request) {
			throw new IllegalArgumentException("The request is nulll,can't execute request.");
		}
		return httpClient.execute(request);
	}
	
	/**
	 * 用于释放请求的连接
	 * @param request
	 */
	public void releaseConnection(HttpRequestBase request) {
		// 判断连接为不为空时释放连接
		if (request != null) {
			request.abort();
			request.releaseConnection();
		}
	}
	
	/**
	 * 关闭连接
	 */
	public void shutdownConnection() {
		if (httpClient != null) {
			httpClient.getConnectionManager().shutdown();
		}
	}
	
	/**
	 * 关闭连接
	 * @param httpClient
	 */
	public void shutdownConnection(HttpClient httpClient) {
		if (httpClient != null) {
			httpClient.getConnectionManager().shutdown();
		}
	}
	
	/**
	 * get请求获取数据
	 * @param url URL地址
	 * @return 返回结果集
	 * @throws IOException
	 */
	public String get(String url) throws IOException {  
        HttpGet httpGet = new HttpGet(url);  
        try{
        	HttpResponse httpResponse = httpClient.execute(httpGet);
            return this.getContent(httpResponse);
        }finally{
        	this.releaseConnection(httpGet);
        }
    }  
	
	/**
	 * post表单提交参数
	 * @param url URL地址
	 * @param params 参数
	 * @return 返回页面结果
	 * @throws IOException
	 */
	public String postForm(String url, Map<String, String> params) throws IOException{  
		HttpPost httPost = new HttpPost(url);  
        try{
        	List<NameValuePair> nvps = new ArrayList<NameValuePair>();  
            Set<String> keySet = params.keySet();  
            for(String key : keySet) {  
            	nvps.add(new BasicNameValuePair(key, params.get(key)));  
            }
            httPost.setEntity(new UrlEncodedFormEntity(nvps, CHARSET));  
            HttpResponse httpResponse = httpClient.execute(httPost);
            return this.getContent(httpResponse);
        }finally{
        	this.releaseConnection(httPost);
        }
    }
	
	/**
	 * post表单提交带附件处理
	 * @param url URL地址
	 * @param params 表单参数
	 * @param filelist 上传附件信息列表
	 * @return 返回页面结果
	 * @throws IOException 
	 */
	public String postMultipart(String url, Map<String, String> params,Map<String,File> fileMap) throws IOException{
		HttpPost httPost = new HttpPost(url);
		try{
			//MultipartEntity：用来上传文件的类
			MultipartEntity entity = new MultipartEntity();
			for (Entry<String, String> entry : params.entrySet()) {
				StringBody stringBody = new StringBody(entry.getValue());
				entity.addPart(entry.getKey(), stringBody);
			}
			for (Entry<String, File> entry : fileMap.entrySet()) {
				FileBody fileBody = new FileBody(entry.getValue());
				entity.addPart(entry.getKey(), fileBody);
			}
			httPost.setEntity(entity);
			HttpResponse httpResponse = httpClient.execute(httPost);  
			return this.getContent(httpResponse);
		}finally{
        	this.releaseConnection(httPost);
        }
	}
	
	/**
	 * json方式请求处理
	 * @param url 地址
	 * @param obj post json数据
	 * @return
	 * @throws IOException
	 */
	public String postJson(String url,Object obj) throws IOException{
		String requestBody = JsonBinder.buildNormalBinder().toJson(obj);
		HttpPost httpPost = new HttpPost(url);
		//添加参数 
		StringEntity requestEntity = new StringEntity(requestBody,ContentType.APPLICATION_JSON);  
        httpPost.setEntity(requestEntity);  
        HttpResponse httpResponse = httpClient.execute(httpPost);
		return this.getContent(httpResponse);
	}

}
